using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;

using Tino.Core;

namespace Tino
{
    public partial class TagsSelectionForm : Form
    {
        const char TAG_NAME_SEPARATOR = ';';

        protected enum SynchronizationWay
        {
            InputToList,
            ListToInput
        }

        /// <summary>
        /// Get the user's selection
        /// </summary>
        public TagsListItemsCollection SelectedTags
        {
            get
            {
                TagsListItemsCollection list = new TagsListItemsCollection();
                foreach (TagsListItem item in tagsList.CheckedItems)
                    list.Add(item);
                
                return list;
            }
        }

        public TagsSelectionForm() : this(null, "") { }

        public TagsSelectionForm(int[] SelectedTagsIDs, string SelectedTags)
        {
            InitializeComponent();

            loadTags(SelectedTagsIDs);
            tagsTextBox.Text = SelectedTags;
            
            // Final UI tasks
            tagsTextBox.TextChanged += new EventHandler(tagsTextBox_TextChanged);
            okButton.Select();
        }

        /// <summary>
        /// Load all the existing Tags into the tagsList CheckedListBox, and checked 
        /// the selected ones.
        /// </summary>
        void loadTags(int[] SelectedTagsIDs)
        {
            GetTagsCommand command = new GetTagsCommand(tagsList, SelectedTagsIDs);
            command.Execute();
        }

        /// <summary>
        /// Save newly created tags
        /// </summary>
        bool Commit()
        {
            foreach (TagsListItem item in tagsList.CheckedItems)
            {
                if (item.ID == -1)
                {
                    TagElement tagElt = new TagElement();
                    int id = 0;
                    try
                    {
                        id = tagElt.AddTag(item.Name);
                        item.ID = id;
                    }
                    catch (Exception)
                    {
                        MessageBox.Show(string.Format("Error saving tag {0}.", item.Name));
                        return false;
                    }
                }
            }
            return true;
        }

        void Synchronize(SynchronizationWay SynchroWay)
        {
            switch (SynchroWay)
            {
                case SynchronizationWay.InputToList:
                    updateList();
                    break;
                case SynchronizationWay.ListToInput:
                    updateInput();
                    break;
            }
        }

        void updateList()
        {
            string[] items = tagsTextBox.Text.Split(TAG_NAME_SEPARATOR);
            if (items.Length > 0)
            {
                resetCheckedListStatus();
                for (int i = 0; i < items.Length; i++)
                {
                    string item = TagElement.Parse(items[i]);
                    int idx = indexOf(item);
                    if (idx > -1)
                        tagsList.SetItemChecked(idx, true);
                    else
                        tagsList.Items.Add(new TagsListItem(-1, item), true);
                }

            }
        }

        void resetCheckedListStatus()
        {
            for (int i = 0; i < tagsList.Items.Count; i++)
                tagsList.SetItemChecked(i, false);
        }

        /// <summary>
        /// Returns the index of the given string in the tags list. Returns -1 if the string does not
        /// exist in the list.
        /// </summary>
        int indexOf(string tag)
        {
            for (int i = 0; i < tagsList.Items.Count; i++)
                if (((TagsListItem)tagsList.Items[i]).Name == tag)
                    return i;

            return -1;
        }

        void updateInput()
        {
            StringBuilder sb = new StringBuilder();
            foreach (TagsListItem item in tagsList.CheckedItems)
            {
                if (sb.Length > 0) sb.AppendFormat("{0} ", TAG_NAME_SEPARATOR);
                sb.Append(item.Name);
            }
            tagsTextBox.Text = sb.ToString();
        }

        #region Form event handlers

        void Form_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.KeyCode == Keys.Escape)
            {
                DialogResult = DialogResult.Cancel;
                Close();
            }
        }

        void tagsTextBox_TextChanged(object sender, EventArgs e)
        {
            TextBox t = (TextBox)sender;
            addToListButton.Enabled = (t.Text != "");
        }

        void tagsTextBox_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.KeyCode == Keys.Enter)
            {
                Synchronize(SynchronizationWay.InputToList);
                if (Commit())
                {
                    DialogResult = DialogResult.OK;
                    Close();
                }
            }
        }

        void tagsList_SelectedIndexChanged(object sender, EventArgs e)
        {
            Synchronize(SynchronizationWay.ListToInput);
        }

        void addToListButton_Click(object sender, EventArgs e)
        {
            Synchronize(SynchronizationWay.InputToList);
        }

        void okButton_Click(object sender, EventArgs e)
        {
            if (Commit())
            {
                DialogResult = DialogResult.OK;
                Close();
            }
        }

        void cancelButton_Click(object sender, EventArgs e)
        {
            DialogResult = DialogResult.Cancel;
            Close();
        }

        void administrateTagsButton_Click(object sender, EventArgs e)
        {
            TagsAdministrationForm admin = new TagsAdministrationForm();
            if (admin.ShowDialog() == DialogResult.OK)
            {
                // Remove deleted tags from the list, and from the input if they were checked.
                foreach (TagsListItem item in admin.DeletedItems)
                {
                    int idx = indexOf(item.Name);
                    if (idx > -1)
                        tagsList.Items.RemoveAt(idx);
                }
                
                // Add created tags to the list
                foreach (TagsListItem item in admin.AddedItems)
                {
                    tagsList.Items.Add(item);
                }

                // Refresh
                Synchronize(SynchronizationWay.ListToInput);
            }
        }

        #endregion
    }
}